package com.my.net;

import com.alibaba.fastjson2.JSON;
import com.my.holder.ContextHolder;
import com.my.resquest.NettyHttpRequest;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.*;
import io.netty.util.AttributeKey;
import io.netty.util.CharsetUtil;

import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * @author WangLuoXin
 * &#064;Date 2024/9/19  10:15
 **/
public class HTTP {

    /**
     * 转发URL 请求
     *
     * @param url              转发请求
     * @param nettyHttpRequest 客户端request
     */
    public static void forward(URL url, NettyHttpRequest nettyHttpRequest) {
        ChannelHandlerContext ctx = ContextHolder.getContext();
        ctx.channel().attr(AttributeKey.valueOf(Boolean.class, "isContinue")).set(Boolean.FALSE);
        // 创建新的 EventLoopGroup
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new HttpClientInitializer(ctx));
            // 连接目标服务器
            ChannelFuture future = bootstrap.connect(url.getHost(), url.getPort() < 0 ? 80 : url.getPort()).sync();
            // 创建 HTTP 请求
            FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, url.getPath());
            request.headers().set(HttpHeaderNames.HOST, url.getHost());
            request.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
            // 发送请求
            future.channel().writeAndFlush(request);
            // 等待关闭连接
            future.channel().closeFuture().sync();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            group.shutdownGracefully();
        }
    }

    /**
     * 发起重定向
     *
     * @param redirectUrl 重定向地址
     */
    public static void redirect(String redirectUrl) {
        ChannelHandlerContext context = ContextHolder.getContext();
        // Create a redirect response
        FullHttpResponse response = new DefaultFullHttpResponse(
                HttpVersion.HTTP_1_1,
                HttpResponseStatus.FOUND,
                Unpooled.EMPTY_BUFFER
        );

        // Set the Location header to the redirect URL
        response.headers().set(HttpHeaderNames.LOCATION, redirectUrl);
        response.headers().set(HttpHeaderNames.CONTENT_LENGTH, 0);
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN);
        context.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }


    /**
     * 返回浏览器数据
     *
     * @param data   json 数据
     * @param status http状态码
     */
    public static void sendData(String data, HttpResponseStatus status) {
        FullHttpResponse response;
        // 创建http响应
        if (null == data || data.isEmpty()) {
            response = new DefaultFullHttpResponse(
                    HttpVersion.HTTP_1_1,
                    status);
        } else {
            response = new DefaultFullHttpResponse(
                    HttpVersion.HTTP_1_1,
                    status,
                    Unpooled.copiedBuffer(JSON.toJSONString(data), CharsetUtil.UTF_8));
        }
        // 设置头信息
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON + "; charset=UTF-8");
        ContextHolder.getContext().writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }

    public static <T> T POST(URL url, String body, Class<T> clazz) {
        final BlockingQueue<T> queue = new ArrayBlockingQueue<>(1);
        // 创建新的 EventLoopGroup
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<Channel>() {
                        @Override
                        protected void initChannel(Channel ch) {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new HttpClientCodec());
                            pipeline.addLast(new HttpObjectAggregator(1048576));
                            pipeline.addLast(new SimpleChannelInboundHandler<FullHttpResponse>() {
                                @Override
                                protected void channelRead0(ChannelHandlerContext ctx, FullHttpResponse response) throws InterruptedException {
                                    ByteBuf content = response.content();
                                    int len = content.readableBytes();
                                    byte[] arr = new byte[len];
                                    content.getBytes(0, arr);
                                    String msg = new String(arr, StandardCharsets.UTF_8);
                                    queue.put(clazz.cast(msg));
                                }
                            });
                        }
                    });
            // 连接目标服务器
            ChannelFuture future = bootstrap.connect(url.getHost(), url.getPort() < 0 ? 80 : url.getPort()).sync();
            String query = url.getQuery();
            if (null == query || query.isEmpty()) {
                query = "";
            } else {
                query = "?" + query;
            }
            ByteBuf bbuf;
            if (body == null) {
                bbuf = Unpooled.buffer(0);
            } else {
                bbuf = Unpooled.copiedBuffer(body, CharsetUtil.UTF_8);
            }
            // 创建 HTTP 请求
            FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1,
                    HttpMethod.POST,
                    url.getPath() + query,
                    bbuf);
            request.headers().set(HttpHeaderNames.HOST, url.getHost());
            request.headers().set(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON + "; charset=UTF-8");
            request.headers().add(HttpHeaderNames.CONTENT_LENGTH, bbuf.readableBytes());
            request.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
            // 发送请求
            future.channel().writeAndFlush(request);
            // 等待关闭连接
            future.channel().closeFuture().sync();
            return queue.take();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            group.shutdownGracefully();
        }
    }


    public static <T> T GET(URL url, Class<T> clazz) {
        final BlockingQueue<T> queue = new ArrayBlockingQueue<>(1);
        // 创建新的 EventLoopGroup
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<Channel>() {
                        @Override
                        protected void initChannel(Channel ch) {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast(new HttpClientCodec());
                            pipeline.addLast(new HttpObjectAggregator(1048576));
                            pipeline.addLast(new SimpleChannelInboundHandler<FullHttpResponse>() {
                                @Override
                                protected void channelRead0(ChannelHandlerContext ctx, FullHttpResponse response) throws InterruptedException {
                                    ByteBuf content = response.content();
                                    int len = content.readableBytes();
                                    byte[] arr = new byte[len];
                                    content.getBytes(0, arr);
                                    String msg = new String(arr, StandardCharsets.UTF_8);
                                    queue.put(clazz.cast(msg));
                                }
                            });
                        }
                    });
            // 连接目标服务器
            ChannelFuture future = bootstrap.connect(url.getHost(), url.getPort() < 0 ? 80 : url.getPort()).sync();
            String query = url.getQuery();
            if (null == query || query.isEmpty()) {
                query = "";
            } else {
                query = "?" + query;
            }
            // 创建 HTTP 请求
            FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, query);
            request.headers().set(HttpHeaderNames.HOST, url.getHost());
            request.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
            // 发送请求
            future.channel().writeAndFlush(request);
            // 等待关闭连接
            future.channel().closeFuture().sync();
            return queue.take();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            group.shutdownGracefully();
        }
    }

}
